import os
import uuid
from flask import Flask, request, jsonify, send_from_directory
from flask_cors import CORS
import docx
from pdf2image import convert_from_path
from PIL import Image
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.fonts import addMapping
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# 新增PDF转换功能所需的库
import pypdf
import pdfplumber
import pandas as pd
from pptx import Presentation
from pptx.util import Inches, Pt
import io
from openpyxl import load_workbook

app = Flask(__name__)
CORS(app)

# 配置上传和输出目录
UPLOAD_FOLDER = 'uploads'
OUTPUT_FOLDER = 'outputs'
ALLOWED_WORD_EXTENSIONS = {'docx', 'doc'}
ALLOWED_PDF_EXTENSION = {'pdf'}
ALLOWED_EXCEL_EXTENSIONS = {'xlsx', 'xls'}
ALLOWED_PPT_EXTENSIONS = {'pptx', 'ppt'}
ALLOWED_IMAGE_EXTENSIONS = {'png', 'jpg', 'jpeg', 'bmp'}

# 创建目录
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(OUTPUT_FOLDER, exist_ok=True)

# 配置应用
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['OUTPUT_FOLDER'] = OUTPUT_FOLDER

# 确保有足够的中文字体支持
try:
    from PIL import ImageFont
    import matplotlib
    matplotlib.use('Agg')  # 使用非交互式后端
    import matplotlib.pyplot as plt
    plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
except:
    print("无法设置matplotlib字体，但仍可继续运行")

# 检查文件扩展名
def allowed_file(filename, conversion_type):
    if not filename or '.' not in filename:
        return False
    file_ext = filename.rsplit('.', 1)[1].lower()
    
    if conversion_type == 'wordToPdf':
        return file_ext in ALLOWED_WORD_EXTENSIONS
    elif conversion_type in ['pdfToImage', 'pdfToWord', 'pdfToExcel', 'pdfToPpt']:
        return file_ext in ALLOWED_PDF_EXTENSION
    elif conversion_type == 'wordToImage':
        return file_ext in ALLOWED_WORD_EXTENSIONS
    elif conversion_type == 'excelToImage':
        return file_ext in ALLOWED_EXCEL_EXTENSIONS
    elif conversion_type == 'pptToImage':
        return file_ext in ALLOWED_PPT_EXTENSIONS
    return False

# 上传文件
def upload_file():
    if 'file' not in request.files:
        return None, '没有文件部分'
    file = request.files['file']
    if file.filename == '':
        return None, '没有选择文件'
    conversion_type = request.form.get('conversion_type', '')
    if file and allowed_file(file.filename, conversion_type):
        filename = str(uuid.uuid4()) + '_' + file.filename
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        file.save(file_path)
        return file_path, None
    else:
        return None, '不支持的文件类型'

# Word 转 PDF 函数
def convert_word_to_pdf(word_path, pdf_path):
    try:
        # 创建PDF文档
        doc = SimpleDocTemplate(pdf_path, pagesize=letter)
        styles = getSampleStyleSheet()
        story = []
        
        # 注册并设置中文字体
        try:
            # 尝试使用系统中可能存在的中文字体
            # Windows系统
            if os.name == 'nt':
                # 尝试加载Windows系统中的中文字体
                system_font_paths = [
                    r'C:\Windows\Fonts\simhei.ttf',  # 黑体
                    r'C:\Windows\Fonts\simsun.ttc',  # 宋体
                    r'C:\Windows\Fonts\msyh.ttc',   # 微软雅黑
                ]
                font_loaded = False
                for font_path in system_font_paths:
                    if os.path.exists(font_path):
                        font_name = os.path.basename(font_path).split('.')[0]
                        pdfmetrics.registerFont(TTFont(font_name, font_path))
                        addMapping(font_name, 0, 0, font_name)  # regular
                        addMapping(font_name, 1, 0, font_name)  # bold
                        styles['Normal'].fontName = font_name
                        font_loaded = True
                        break
                
                # 如果没有找到中文字体，使用reportlab内置字体加后备方案
                if not font_loaded:
                    # 尝试使用默认字体加编码方案
                    styles['Normal'].fontName = 'Helvetica'
            else:
                # 非Windows系统使用默认字体
                styles['Normal'].fontName = 'Helvetica'
        except Exception as font_error:
            print(f"设置字体时出错: {str(font_error)}")
            # 出错时使用默认设置
            pass
        
        # 读取Word文档
        docx_doc = docx.Document(word_path)
        
        # 遍历文档中的段落
        for para in docx_doc.paragraphs:
            if para.text.strip():
                # 添加段落到PDF
                story.append(Paragraph(para.text, styles['Normal']))
                story.append(Spacer(1, 12))
        
        # 遍历文档中的表格
        for table in docx_doc.tables:
            for row in table.rows:
                row_text = []
                for cell in row.cells:
                    row_text.append(cell.text.strip())
                if any(row_text):
                    story.append(Paragraph(' | '.join(row_text), styles['Normal']))
                    story.append(Spacer(1, 12))
        
        # 构建PDF
        doc.build(story)
        return True
    except Exception as e:
        print(f"Word转PDF失败: {str(e)}")
        return False

# PDF 转图片函数
def convert_pdf_to_images(pdf_path, poppler_path=None):
    try:
        # 获取PDF文件名（不含扩展名）
        pdf_name = os.path.splitext(os.path.basename(pdf_path))[0]
        
        # 转换PDF为图片列表
        # 如果提供了poppler_path，则使用该路径
        convert_kwargs = {}
        if poppler_path:
            convert_kwargs['poppler_path'] = poppler_path
        
        images = convert_from_path(pdf_path, **convert_kwargs)
        
        # 保存每张图片
        image_paths = []
        for i, image in enumerate(images):
            image_filename = f"{pdf_name}_page_{i+1}.png"
            image_path = os.path.join(app.config['OUTPUT_FOLDER'], image_filename)
            image.save(image_path, 'PNG')
            image_paths.append(image_filename)
        
        return image_paths
    except Exception as e:
        error_msg = str(e)
        print(f"PDF转图片失败: {error_msg}")
        
        # 特殊处理Poppler未安装的错误
        if "Unable to get page count" in error_msg or "poppler" in error_msg.lower():
            return ["ERROR_POPPLER_MISSING"]
        
        return []

# PDF 转 Word 函数
def convert_pdf_to_word(pdf_path, word_path):
    try:
        # 使用pdfplumber提取文本内容
        text_content = ""
        with pdfplumber.open(pdf_path) as pdf:
            for page in pdf.pages:
                # 提取页面文本
                text = page.extract_text()
                if text:
                    text_content += text + "\n\n"
        
        # 创建Word文档
        doc = docx.Document()
        
        # 将提取的文本按段落添加到Word文档
        paragraphs = text_content.split("\n\n")
        for para_text in paragraphs:
            if para_text.strip():
                doc.add_paragraph(para_text.strip())
        
        # 保存Word文档
        doc.save(word_path)
        return True
    except Exception as e:
        print(f"PDF转Word失败: {str(e)}")
        return False

# PDF 转 Excel 函数
def convert_pdf_to_excel(pdf_path, excel_path):
    try:
        # 创建一个Excel写入对象
        excel_writer = pd.ExcelWriter(excel_path, engine='xlsxwriter')
        
        # 计数器，用于创建多个工作表
        sheet_count = 1
        
        with pdfplumber.open(pdf_path) as pdf:
            for page_number, page in enumerate(pdf.pages, 1):
                # 尝试提取表格
                tables = page.extract_tables()
                if tables:
                    for table_index, table in enumerate(tables):
                        # 创建工作表名称
                        sheet_name = f'Sheet_{sheet_count}_{page_number}_{table_index+1}'
                        if len(sheet_name) > 31:  # Excel工作表名称长度限制
                            sheet_name = sheet_name[:31]
                        
                        # 创建DataFrame并保存到Excel
                        df = pd.DataFrame(table)
                        # 设置第一行为表头
                        if not df.empty:
                            df.columns = df.iloc[0]
                            df = df[1:]
                            df.to_excel(excel_writer, sheet_name=sheet_name, index=False)
                            sheet_count += 1
                
            # 如果没有提取到表格，尝试提取文本并保存到一个工作表
            if sheet_count == 1:
                text_content = ""
                for page in pdf.pages:
                    text = page.extract_text()
                    if text:
                        text_content += text + "\n\n"
                
                # 将文本按行分割并保存
                if text_content.strip():
                    lines = text_content.strip().split('\n')
                    df_text = pd.DataFrame(lines, columns=['Text'])
                    df_text.to_excel(excel_writer, sheet_name='Extracted_Text', index=False)
        
        # 保存Excel文件
        excel_writer.close()
        return True
    except Exception as e:
        print(f"PDF转Excel失败: {str(e)}")
        return False

# PDF 转 PPT 函数
def convert_pdf_to_ppt(pdf_path, ppt_path):
    try:
        # 创建PPT文档
        prs = Presentation()
        
        with pdfplumber.open(pdf_path) as pdf:
            for page_number, page in enumerate(pdf.pages, 1):
                # 提取文本内容
                text = page.extract_text()
                
                # 创建幻灯片
                slide_layout = prs.slide_layouts[5]  # 空白布局
                slide = prs.slides.add_slide(slide_layout)
                
                # 添加页面标题
                if page_number <= len(prs.slide_master.placeholders):
                    title = slide.shapes.title
                    title.text = f"Page {page_number}"
                else:
                    # 如果没有标题占位符，创建一个文本框
                    left = Inches(1)
                    top = Inches(0.5)
                    width = Inches(8)
                    height = Inches(1)
                    txBox = slide.shapes.add_textbox(left, top, width, height)
                    tf = txBox.text_frame
                    p = tf.add_paragraph()
                    p.text = f"Page {page_number}"
                    p.font.size = Pt(24)
                
                # 添加文本内容
                if text:
                    left = Inches(1)
                    top = Inches(1.5)
                    width = Inches(8)
                    height = Inches(5)
                    txBox = slide.shapes.add_textbox(left, top, width, height)
                    tf = txBox.text_frame
                    
                    # 分割文本并添加到段落
                    paragraphs = text.split('\n')
                    for para_text in paragraphs:
                        if para_text.strip():
                            p = tf.add_paragraph()
                            p.text = para_text.strip()
                            p.font.size = Pt(18)
                
        # 保存PPT文档
        prs.save(ppt_path)
        return True
    except Exception as e:
        print(f"PDF转PPT失败: {str(e)}")
        return False

# Word 转图片函数
def convert_word_to_images(word_path):
    try:
        # 获取Word文件名（不含扩展名）
        word_name = os.path.splitext(os.path.basename(word_path))[0]
        
        # 先将Word转换为临时PDF
        temp_pdf_path = os.path.join(app.config['OUTPUT_FOLDER'], f"{word_name}_temp.pdf")
        if not convert_word_to_pdf(word_path, temp_pdf_path):
            return []
        
        # 配置Poppler路径
        poppler_path = r'd:\work\AiDocMaster\poppler-25.07.0\Library\bin'
        
        # 再将PDF转换为图片，传递Poppler路径
        image_paths = convert_pdf_to_images(temp_pdf_path, poppler_path)
        
        # 删除临时PDF文件
        if os.path.exists(temp_pdf_path):
            os.remove(temp_pdf_path)
        
        return image_paths
    except Exception as e:
        print(f"Word转图片失败: {str(e)}")
        return []

# Excel 转图片函数
def convert_excel_to_images(excel_path):
    try:
        # 获取Excel文件名（不含扩展名）
        excel_name = os.path.splitext(os.path.basename(excel_path))[0]
        
        # 加载Excel文件
        workbook = load_workbook(excel_path)
        image_paths = []
        
        # 遍历所有工作表
        for sheet_name in workbook.sheetnames:
            sheet = workbook[sheet_name]
            
            # 创建图形
            plt.figure(figsize=(12, 8))
            plt.title(sheet_name, fontsize=16)
            
            # 获取数据范围
            data = []
            for row in sheet.iter_rows(values_only=True):
                if any(cell is not None for cell in row):  # 跳过空行
                    data.append(row)
            
            # 如果有数据，创建表格可视化
            if data:
                # 计算表格位置和大小
                n_rows, n_cols = len(data), len(max(data, key=len))
                
                # 创建表格
                table = plt.table(cellText=data, loc='center')
                table.auto_set_font_size(False)
                table.set_fontsize(10)
                table.scale(1.2, 1.2)
                
                # 隐藏坐标轴
                plt.axis('off')
                
                # 保存为图片
                image_filename = f"{excel_name}_{sheet_name}.png".replace('/', '_').replace('\\', '_')
                image_path = os.path.join(app.config['OUTPUT_FOLDER'], image_filename)
                plt.tight_layout()
                plt.savefig(image_path, dpi=300, bbox_inches='tight')
                plt.close()
                
                image_paths.append(image_filename)
        
        return image_paths
    except Exception as e:
        print(f"Excel转图片失败: {str(e)}")
        return []

# PPT 转图片函数
def convert_ppt_to_images(ppt_path):
    try:
        # 获取PPT文件名（不含扩展名）
        ppt_name = os.path.splitext(os.path.basename(ppt_path))[0]
        
        # 加载PPT文件
        prs = Presentation(ppt_path)
        image_paths = []
        
        # 遍历所有幻灯片
        for i, slide in enumerate(prs.slides):
            # 创建一个字节流来保存图片
            img_byte_arr = io.BytesIO()
            
            # 将幻灯片保存为图片
            slide.shapes._spTree.write_image(img_byte_arr)
            
            # 读取图片并保存到文件
            img = Image.open(img_byte_arr)
            image_filename = f"{ppt_name}_slide_{i+1}.png"
            image_path = os.path.join(app.config['OUTPUT_FOLDER'], image_filename)
            img.save(image_path, 'PNG')
            
            image_paths.append(image_filename)
        
        return image_paths
    except Exception as e:
        print(f"PPT转图片失败: {str(e)}")
        return []

# API 路由：文件上传和转换
@app.route('/api/convert', methods=['POST'])
def convert_document():
    # 上传文件
    file_path, error = upload_file()
    if error:
        return jsonify({'error': error}), 400
    
    conversion_type = request.form.get('conversion_type', '')
    
    # 获取原始文件名（不含唯一ID前缀）
    original_filename = '_'.join(os.path.basename(file_path).split('_')[1:])
    unique_id = os.path.basename(file_path).split('_')[0]
    
    # 根据转换类型执行相应的转换
    if conversion_type == 'wordToPdf':
        # Word 转 PDF
        pdf_filename = f"{unique_id}_{os.path.splitext(original_filename)[0]}.pdf"
        pdf_path = os.path.join(app.config['OUTPUT_FOLDER'], pdf_filename)
        
        if convert_word_to_pdf(file_path, pdf_path):
            # 删除上传的Word文件
            os.remove(file_path)
            return jsonify({'success': True, 'filename': pdf_filename})
        else:
            return jsonify({'error': 'Word转PDF失败'}), 500
    elif conversion_type == 'pdfToImage':
        # PDF 转图片
        # 配置Poppler路径（用户已下载）
        poppler_path = r'd:\work\AiDocMaster\poppler-25.07.0\Library\bin'
        
        # 尝试转换PDF为图片
        image_paths = convert_pdf_to_images(file_path, poppler_path)
        
        # 检查是否有特殊错误标识
        if image_paths and image_paths[0] == "ERROR_POPPLER_MISSING":
            # Poppler未安装或未配置的错误
            return jsonify({
                'error': 'PDF转图片功能需要安装Poppler工具',
                'details': '请下载并安装Poppler，然后将其bin目录添加到系统PATH环境变量中。\nWindows用户可从 https://github.com/oschwartz10612/poppler-windows/releases 下载。',
                'type': 'POPPLER_MISSING'
            }), 500
        elif image_paths:
            # 转换成功
            # 删除上传的PDF文件
            os.remove(file_path)
            return jsonify({
                'success': True,
                'image_count': len(image_paths),
                'image_files': image_paths
            })
        else:
            return jsonify({'error': 'PDF转图片失败'}), 500
    elif conversion_type == 'pdfToWord':
        # PDF 转 Word
        word_filename = f"{unique_id}_{os.path.splitext(original_filename)[0]}.docx"
        word_path = os.path.join(app.config['OUTPUT_FOLDER'], word_filename)
        
        if convert_pdf_to_word(file_path, word_path):
            # 删除上传的PDF文件
            os.remove(file_path)
            return jsonify({'success': True, 'filename': word_filename})
        else:
            return jsonify({'error': 'PDF转Word失败'}), 500
    elif conversion_type == 'pdfToExcel':
        # PDF 转 Excel
        excel_filename = f"{unique_id}_{os.path.splitext(original_filename)[0]}.xlsx"
        excel_path = os.path.join(app.config['OUTPUT_FOLDER'], excel_filename)
        
        if convert_pdf_to_excel(file_path, excel_path):
            # 删除上传的PDF文件
            os.remove(file_path)
            return jsonify({'success': True, 'filename': excel_filename})
        else:
            return jsonify({'error': 'PDF转Excel失败'}), 500
    elif conversion_type == 'pdfToPpt':
        # PDF 转 PPT
        ppt_filename = f"{unique_id}_{os.path.splitext(original_filename)[0]}.pptx"
        ppt_path = os.path.join(app.config['OUTPUT_FOLDER'], ppt_filename)
        
        if convert_pdf_to_ppt(file_path, ppt_path):
            # 删除上传的PDF文件
            os.remove(file_path)
            return jsonify({'success': True, 'filename': ppt_filename})
        else:
            return jsonify({'error': 'PDF转PPT失败'}), 500
    elif conversion_type == 'wordToImage':
        # Word 转图片
        image_paths = convert_word_to_images(file_path)
        
        if image_paths:
            # 删除上传的Word文件
            os.remove(file_path)
            return jsonify({
                'success': True,
                'image_count': len(image_paths),
                'image_files': image_paths
            })
        else:
            return jsonify({'error': 'Word转图片失败'}), 500
    elif conversion_type == 'excelToImage':
        # Excel 转图片
        image_paths = convert_excel_to_images(file_path)
        
        if image_paths:
            # 删除上传的Excel文件
            os.remove(file_path)
            return jsonify({
                'success': True,
                'image_count': len(image_paths),
                'image_files': image_paths
            })
        else:
            return jsonify({'error': 'Excel转图片失败'}), 500
    elif conversion_type == 'pptToImage':
        # PPT 转图片
        image_paths = convert_ppt_to_images(file_path)
        
        if image_paths:
            # 删除上传的PPT文件
            os.remove(file_path)
            return jsonify({
                'success': True,
                'image_count': len(image_paths),
                'image_files': image_paths
            })
        else:
            return jsonify({'error': 'PPT转图片失败'}), 500
    else:
        return jsonify({'error': '无效的转换类型'}), 400

# API 路由：文件下载
@app.route('/api/download/<filename>', methods=['GET'])
def download_file(filename):
    try:
        return send_from_directory(app.config['OUTPUT_FOLDER'], filename, as_attachment=True)
    except FileNotFoundError:
        return jsonify({'error': '文件未找到'}), 404

# 主页路由
@app.route('/')
def home():
    return jsonify({'message': '欢迎使用文档转换系统API'})

if __name__ == '__main__':
    # 生产环境请设置debug=False
    app.run(debug=True, host='0.0.0.0', port=5000)